/******************************************************************************
*  COPYRIGHT MorningCore CO.,LTD
******************************************************************************/

/*****************************************************************
 * FileName::    RSGen.c
 * version::     1.0.0
 * Purpose:      Cyclic shifted sequence generation for DMRS, SRS and PUCCH
 * Authors:      zhangshanzhong, 2008-12-18
 * Notes:        None
 ******************************************************************/

/******************************************************************************
*  HISTORY OF CHANGES
*   <Date>          <Author>        <Version>       <DESCRIPTION>
*   2008-12-18      zhangshanzhong  V1.0.0           original
*   2009-11-2       zhangyanan      V1.0.1           Modify bug of RB_Num=1,2
******************************************************************************/

/******************************************************************************
*  INCLUDE FILES
******************************************************************************/
#include "../head/ue_tx_rsgen_fix.h"
#include "../../SRS/ue_tx_srs_Print.h"


/*----------- function definition-----------------------------------*/
/*****************************************************************************
* Function: RSGen()
* Purpose:  This function performs cyclic shift sequence generation for DMRS, SRS
*           and PUCCH
*
* Relation:
            Calls       : ....
            Called by   : ....
* Params:
*   <Name>                  <Type>      <In/Out>    <Description>
*   ZCRootSeqGen_Op[1320]   cmplx_frN   In          Zadoff-Chu root sequence
*   RootSeqLen              int         In          length of root seq
*   RS_SC_Num               int         In          number of sub-carriers of RS
*   Ncs                     int         In          Cyclic shift param in 3GPP TS 38.211
*   uIdx                  int         In          Sequence index for short base seq
*   SRS_Flag                int         In          whether SRS flag
*   N_RotateCoef            int8        In          processing bit width
*   RSGen_Op[1320]          cmplx_frN   Out         output of RSGen
* Return:  void
* Note:    None
*******************************************************************************/
void RSGen_fix_ReleaseFlag
(
    IN int      UL_RB_Num,                  // number of sub-carriers of RS
    IN int      Ncs,                        // Cyclic shift param in 3GPP TS 38.211
    IN int      Omiga,                      // Omiga in 3GPP TS 38.211
    IN int      Delta,                      // Delta in 3GPP TS 38.211
    IN int      uIdx,                       // u in 3GPP TS 38.211
    IN int      vIdx,                       // v in 3GPP TS 38.211
    IN int      RS_Type,             // alpha = 2*pi*Ncs/12 for 0; alpha = 2*pi*Ncs/8 for 1
    IN char     mul_ncs_flg,         //mul_ncs_flg=0,mean no need multiply ncs
    IN int      N_RotateCoef,
    OUT cmplx_frN   RSGen_Op[]           // output of RSGen
)
{
    /*variables definition*/
    cmplx_frN BaseSeq[MAXRBNUM * 12]; // base sequence Q(N,1)
    int32 DividParam; // input dividend parameter
    cmplx_frN CS_Param;
	cmplx_frN CS_Param_table[MAXRBNUM * 12];//just for srs print
    cmplx_frN ZCRootSeqGen_Op[MAXRBNUM * 12]; // Zadoff-Chu root sequence
    int     RS_SC_Num = 0;      // Rs length
    int   i; // loop index
    int16 divisor = 0;
    int   RootSeqParam = 0;  // u (PRACH) or q (RS) in 3GPP TS 38.211
    float RootSeqParamTemp; // for calc u
    int   RootSeqLen = 0;                   // length of root seq

    set_rnd_mode_floor();

    int   BitWidth;
    fractN CS_Re[2][12] = {{8191, 7094, 4096, 0, -4096, -7094, -8192, -7094, -4096, 0, 4096, 7094},
        {8191, 5793, 0, -5793, -8192, -5793, 0, 5793}
    };
    fractN CS_Im[2][12] = {{0, 4096, 7094, 8191, 7094, 4096, 0, -4096, -7094, -8192, -7094, -4096},
        {0, 5793, 8191, 5793, 0, -5793, -8192, -5793}
    };

    int BsSeqTable = 0;

    /*Function body*/
    BitWidth = N_RotateCoef;
    Set_bit_width(BitWidth);
    // RS length
    RS_SC_Num = (int)(UL_RB_Num * 12 / pow(2.0, Delta));
    // determine base sequence according to length
    if (RS_SC_Num >= 30) // Sequence length >= 30
    {
        // update RootSeqLen according to UL_RB_Num
        if (0 == Delta) // 0
        {
            RootSeqLen = PrimTable_Delta0[UL_RB_Num - 1];
        }
        else if (1 == Delta) // 1
        {
            RootSeqLen = PrimTable_Delta1[UL_RB_Num - 1];
        }
        else    // 1
        {
            RootSeqLen = PrimTable_Delta2[UL_RB_Num - 1];
        }

        if (30 == RS_SC_Num) // q*(n+1)*(n+2)/31, q = u + 1
        {
            RootSeqParam = uIdx + 1; // q
            RootSeqLen = 31;

			ZCRootSeqGen_fix
			(
				RootSeqLen,	  // 839 or 139 only for PRACH
				RootSeqParam, // u (PRACH) or q (RS) in 3GPP TS 38.211
				BitWidth,
				ZCRootSeqGen_Op, // Zadoff-Chu root sequence
				1
			);
		}
		else // q*n*(n+1)/RootSeqLen
		{
    		RootSeqParamTemp = (float)(RootSeqLen * (uIdx + 1) / 31.0);
    		RootSeqParam = (int)((int)(RootSeqParamTemp + 0.5) + vIdx * pow(-1.0, (int)(2 * RootSeqParamTemp)));	
						// ZC generation
			ZCRootSeqGen_fix
			(  
				RootSeqLen,	  // 839 or 139 only for PRACH
				RootSeqParam, // u (PRACH) or q (RS) in 3GPP TS 38.211
				BitWidth,
				ZCRootSeqGen_Op // Zadoff-Chu root sequence
				);
		}
        // base sequence 
        for(i=0; i<RS_SC_Num; i++)
        {
            BaseSeq[i] = ZCRootSeqGen_Op[i % RootSeqLen];
        }
    }
    else // Sequence length = SCNumPerRB or 2*SCNumPerRB
    {
        for (i = 0; i < RS_SC_Num; i++)
        {

			if (6 == RS_SC_Num) // 6
			{
				BsSeqTable = BsSeqTable6[uIdx][i];
			}
			else if (12 == RS_SC_Num) // 12
			{
				BsSeqTable = BsSeqTable12_V201806[uIdx][i];
			}
			else if (18 == RS_SC_Num) // 18
			{
				BsSeqTable = BsSeqTable18_V201806[uIdx][i];
			}
			else // SCNumPerRB*2
			{
				BsSeqTable = BsSeqTable24_V201806[uIdx][i];
			}

            // get complex value
            if (BsSeqTable == -1)
            {
                BaseSeq[i].re = 5792;
                BaseSeq[i].im = -5792;
            }
            else if (BsSeqTable == 1)
            {
                BaseSeq[i].re = 5792;
                BaseSeq[i].im = 5792;
            }
            else if (BsSeqTable == 3)
            {
                BaseSeq[i].re = -5792;
                BaseSeq[i].im = 5792;
            }
            else if (BsSeqTable == -3)
            {
                BaseSeq[i].re = -5792;
                BaseSeq[i].im = -5792;
            }
        }
		if (UE_SRS_PRINTFLAG)
		{
		  ue_tx_SRS_SEQ_RUV24_Print( BaseSeq, RS_SC_Num);
		}
    }

    // determine cyclic shifted output sequence according to RS_Type
    if (RS_Type == 0) // DMRS
    {
        divisor = 12;
    }
    else if (RS_Type == 1) // SRS
    {
        divisor = 8;
    }
    else
    {
        printf("Error Configuration for SRS flag!");
    }

    // cyclic shift
    if (mul_ncs_flg == 1)
    {
        for (i = 0; i < RS_SC_Num; i++)
        {
            DividParam = (Ncs * i) % divisor;
            CS_Param.re = CS_Re[RS_Type][DividParam];
            CS_Param.im = CS_Im[RS_Type][DividParam];
			CS_Param_table[i] = CS_Param;
            RSGen_Op[i] = Cmlt_frN(CS_Param, BaseSeq[i]);
			ue_tx_SRS_ComplexShift_N_Print(DividParam);	

        }

		if (UE_SRS_PRINTFLAG)
		{
			ue_tx_SRS_ComplexShift_LUT_Print(CS_Param_table,RS_SC_Num);
		}
    }
    else
    {
        for (i = 0; i < RS_SC_Num; i++)
        {
            RSGen_Op[i] = BaseSeq[i];
        }
    }
 if (UE_SRS_PRINTFLAG)
	{
		ue_tx_SRS_SEQ_RUV_Print( BaseSeq, RS_SC_Num);
		ue_tx_SRS_SEQ_RNL_Print(RSGen_Op, RS_SC_Num);
	}
}
/*----------- function definition-----------------------------------*/
/*****************************************************************************
* Function: ZCRootSeqGen()
* Purpose:  This function performs Zadoff-Chu root sequence generation for base
*           sequence generation for RS and preamble sequence for PRACH.
*
* Relation:
            Calls       : RotateCoefGen()
            Called by   : ...
* Params:
*   <Name>                  <Type>      <In/Out>    <Description>
*   RootSeqLen              int         In          Root sequence length
*   RootSeqParam            int         In          Sequence index
*   N_RotateCoef            int8        In          processing bit width
*   ZCRootSeqGen_Op[1320]   cmplx_frN   Out         Output ZC root sequence Q(16,1)
* Return:  void
* Note:    <the limitations to use this function or other comments>
*******************************************************************************/
void ZCRootSeqGen_fix
(
    IN int      RootSeqLen,   // 839 or 139 only for PRACH
    IN int      RootSeqParam, // u (PRACH) or q (RS) in 3GPP TS 38.211
    IN int      N_RotateCoef,
    OUT cmplx_frN	 ZCRootSeqGen_Op[], // Zadoff-Chu root sequence
	IN int      Len30Flag
)	
{
    /*variables definition*/
    int i; // loop index
    int16  dividend; // dividend of input
    uint32 DividParam; // input dividend parameter //modified by shanshan 20100624
    int16  divisor;  // divisor of input
    cmplx_frN TmpResult[1]; // power temperate result Q(N,1)
    int   BitWidth;
    /*Init*/
    BitWidth = N_RotateCoef;
    // set bit width
    Set_bit_width(BitWidth);
    // root sequence length as divisor
    divisor = RootSeqLen;

    /*Function body*/
    for(i=0; i<RootSeqLen; i++)
    {
		if (Len30Flag == 0)
		{
			//DividParam = RootSeqParam * ((i * (i + 1) % (2* RootSeqLen)));
			DividParam = RootSeqParam * ((i * (i + 1) / 2 % RootSeqLen));
		}
		else
		{
			//DividParam = (uint32)(RootSeqParam * ((i + 1) * (i + 2) % (2 * RootSeqLen)));
			DividParam = (uint32)(RootSeqParam * ((i + 1) * (i + 2) / 2 % RootSeqLen));
		}

		dividend = Nzc_2_8192(DividParam, divisor);

		// call cos() - j*sin() function
		exp_1jx2xpixnvs8192_fxptable(TmpResult, dividend, 1, BitWidth);

		ZCRootSeqGen_Op[i] = TmpResult[0];

	}
}

///=================================================================================================
/// Nzc_2_8192.
/// mp = mod(m, 2Nzc), n = mod(m_p*4096/Nzc, 8192)
/// @param [in] int m
/// @param [in] int N_zc
/// @par History
///       Date|       Author|        Version|        DESCRIPTION
/// ----------|-------------|---------------|-------------------
/// 2021-09-17|     shanshan|          0.0.1|            created
///=================================================================================================
int Nzc_2_8192(int m, int Nzc)
{
	int n;
	int zc_idx, Nzc_mul2 = 0;
	int m_p, n_p = 0;
	int64 m_p_temp;

	// find zc_idx to get N_zc_Inv
	switch (Nzc) {
	case 5: zc_idx = 0; break;
	case 11: zc_idx = 1; break;
	case 17: zc_idx = 2; break;
	case 23: zc_idx = 3; break;
	case 29: zc_idx = 4; break;
	case 31: zc_idx = 5; break;
	case 41: zc_idx = 6; break;
	case 47: zc_idx = 7; break;
	case 53: zc_idx = 8; break;
	case 59: zc_idx = 9; break;
	case 61: zc_idx = 10; break;
	case 71: zc_idx = 11; break;
	case 73: zc_idx = 12; break;
	case 83: zc_idx = 13; break;
	case 89: zc_idx = 14; break;
	case 101: zc_idx = 15; break;
	case 107: zc_idx = 16; break;
	case 113: zc_idx = 17; break;
	case 131: zc_idx = 18; break;
	case 137: zc_idx = 19; break;
	case 139: zc_idx = 20; break;
	case 149: zc_idx = 21; break;
	case 151: zc_idx = 22; break;
	case 157: zc_idx = 23; break;
	case 167: zc_idx = 24; break;
	case 173: zc_idx = 25; break;
	case 179: zc_idx = 26; break;
	case 181: zc_idx = 27; break;
	case 191: zc_idx = 28; break;
	case 197: zc_idx = 29; break;
	case 199: zc_idx = 30; break;
	case 211: zc_idx = 31; break;
	case 227: zc_idx = 32; break;
	case 233: zc_idx = 33; break;
	case 239: zc_idx = 34; break;
	case 241: zc_idx = 35; break;
	case 251: zc_idx = 36; break;
	case 257: zc_idx = 37; break;
	case 263: zc_idx = 38; break;
	case 269: zc_idx = 39; break;
	case 271: zc_idx = 40; break;
	case 281: zc_idx = 41; break;
	case 283: zc_idx = 42; break;
	case 293: zc_idx = 43; break;
	case 311: zc_idx = 44; break;
	case 317: zc_idx = 45; break;
	case 331: zc_idx = 46; break;
	case 337: zc_idx = 47; break;
	case 347: zc_idx = 48; break;
	case 353: zc_idx = 49; break;
	case 359: zc_idx = 50; break;
	case 367: zc_idx = 51; break;
	case 373: zc_idx = 52; break;
	case 383: zc_idx = 53; break;
	case 389: zc_idx = 54; break;
	case 401: zc_idx = 55; break;
	case 419: zc_idx = 56; break;
	case 431: zc_idx = 57; break;
	case 443: zc_idx = 58; break;
	case 449: zc_idx = 59; break;
	case 467: zc_idx = 60; break;
	case 479: zc_idx = 61; break;
	case 491: zc_idx = 62; break;
	case 503: zc_idx = 63; break;
	case 509: zc_idx = 64; break;
	case 523: zc_idx = 65; break;
	case 547: zc_idx = 66; break;
	case 563: zc_idx = 67; break;
	case 571: zc_idx = 68; break;
	case 587: zc_idx = 69; break;
	case 599: zc_idx = 70; break;
	case 607: zc_idx = 71; break;
	case 619: zc_idx = 72; break;
	case 631: zc_idx = 73; break;
	case 647: zc_idx = 74; break;
	case 659: zc_idx = 75; break;
	case 661: zc_idx = 76; break;
	case 683: zc_idx = 77; break;
	case 691: zc_idx = 78; break;
	case 701: zc_idx = 79; break;
	case 719: zc_idx = 80; break;
	case 727: zc_idx = 81; break;
	case 743: zc_idx = 82; break;
	case 751: zc_idx = 83; break;
	case 761: zc_idx = 84; break;
	case 773: zc_idx = 85; break;
	case 787: zc_idx = 86; break;
	case 797: zc_idx = 87; break;
	case 809: zc_idx = 88; break;
	case 811: zc_idx = 89; break;
	case 839: zc_idx = 90; break;
	case 863: zc_idx = 91; break;
	case 887: zc_idx = 92; break;
	case 911: zc_idx = 93; break;
	case 929: zc_idx = 94; break;
	case 953: zc_idx = 95; break;
	case 971: zc_idx = 96; break;
	case 983: zc_idx = 97; break;
	case 997: zc_idx = 98; break;
	case 1031: zc_idx = 99; break;
	case 1051: zc_idx = 100; break;
	case 1069: zc_idx = 101; break;
	case 1103: zc_idx = 102; break;
	case 1123: zc_idx = 103; break;
	case 1151: zc_idx = 104; break;
	case 1171: zc_idx = 105; break;
	case 1193: zc_idx = 106; break;
	case 1223: zc_idx = 107; break;
	case 1237: zc_idx = 108; break;
	case 1259: zc_idx = 109; break;
	case 1291: zc_idx = 110; break;
	case 1319: zc_idx = 111; break;
	case 1327: zc_idx = 112; break;
	case 1367: zc_idx = 113; break;
	case 1381: zc_idx = 114; break;
	case 1409: zc_idx = 115; break;
	case 1439: zc_idx = 116; break;
	case 1453: zc_idx = 117; break;
	case 1459: zc_idx = 118; break;
	case 1487: zc_idx = 119; break;
	case 1499: zc_idx = 120; break;
	case 1511: zc_idx = 121; break;
	case 1531: zc_idx = 122; break;
	case 1559: zc_idx = 123; break;
	case 1583: zc_idx = 124; break;
	case 1607: zc_idx = 125; break;
	case 1619: zc_idx = 126; break;
	case 1627: zc_idx = 127; break;
	}

	//Nzc_mul2 = 2 * Nzc; // 2*Nzc
	//m_p = mod_n_N(m, Nzc_mul2, N_zc_Inv[zc_idx]); // mp = mod(qm(m + 1), 2Nzc)
	//m_p_temp = (int64)(m_p) * (int64)(N_zc_Inv[zc_idx]); // 2^31
	//n_p = (int)(m_p_temp >> 19);
	m_p = m % Nzc;
	m_p_temp = (int64)(m_p) * (int64)(N_zc_Inv[zc_idx]);
	n_p = (int)(m_p_temp >> 15); // 
	n = n_p % 8192; // n = mod(m_p * 4096 / Nzc, 8192)

	return n;
}
///=================================================================================================
/// mod_n_N.
/// m = n % N
/// @param [in] int n  
/// @param [in] int N
/// @param [in] int N_zc_Inv_fixp num of 2*Nzc in 2^32
/// @par History
///       Date|       Author|        Version|        DESCRIPTION
/// ----------|-------------|---------------|-------------------
/// 2021-09-17|     shanshan|          0.0.1|            created
///=================================================================================================
int mod_n_N(int n, int N, int N_zc_Inv_fixp)
{
	int m = 0;
	int64 inter_n, inter_n_temp = 0; // num of 2^32 in n

	inter_n_temp = (int64)(n) * (int64)(N_zc_Inv_fixp);
	inter_n = (int64)(inter_n_temp >> 32);
	m = (int)(n - (int)(inter_n * N));

	if (m == N)
	{
		m = 0;
	}

	if (m < 0)
	{
		m = m + N;
	}

	return m;
}
